package com.hellowx_ssm.aop.dynamic;

import com.hellowx_ssm.aop.proxy.User;
import com.hellowx_ssm.aop.proxy.UserService;
import com.hellowx_ssm.aop.proxy.UserServiceImpl;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * Created by IntelliJ IDEA.
 *
 * @author MagicMushroom
 * @date 2021/6/14
 */
public class JdkProxy {
    public static void main(String[] args) {
//    代理创建三要素：
//      创建原始对象
//      创建额外功能
//      代理对象与原始对象实现相同的功能

//    创建原始对象
        UserService userService = new UserServiceImpl();

//        JDK动态代理
//        Proxy.newProxyInstance(classLoader,interfaces,invocationHandler)

//        参数详解：
//        invocationHandler：额外功能
/*        invocationHandler{
               Object invoke(proxy,method,args){
                   ...书写前置额外功能
                   通过反射调用方法
                   ret = method.invoke(UserService,args)
                   ...书写后置额外功能
                   ...对返回参数进行处理
                   return ret;
            }
        }
*/
/*
        interfaces：代理对象与原始对象需要实现相同的接口
        例如：userService.getClass().getInterfaces()
*/
/*
        classLoader:因为JVM不会自动分配，所有需要外部传进来
        普通对象创建的过程：JVM加载.class文件是会分配对应的classLoader
            1.书写.java文件，如User.java
            2.编译为.class文件
            3.JVM通过类加载器（CL）把.class的字节码文件加载进jvm
            4.JVM通过类加载器（CL）创建类的CLass对象
            5.调用new XX（）构造方法创建对象

        动态代理对象创建：
            1.因为没有对应的.java,.class文件，所有自然JVM也没有分配对应的ClassLoader
            2.根据接口，以及借用的classLoader来生成代理对象
 */
        InvocationHandler handler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("before");
                Object ret = method.invoke(userService, args);
                System.out.println("after");
                return ret;
            }
        };

        UserService proxy = (UserService) Proxy.newProxyInstance(JdkProxy.class.getClassLoader(), userService.getClass().getInterfaces(), handler);
        proxy.register(new User());
    }
}
